/**************************************************************************************************
* Title: SumVector4.inl
* Author: Gael Huber
* Description: Mathematical functions for 4D vector
**************************************************************************************************/
/**************************************************************************************************
* Default constructor
**************************************************************************************************/
inline Vector4::Vector4(void)
	: x(0.0f), y(0.0f), z(0.0f), w(0.0f)
{ }

/**************************************************************************************************
* Constructor from array
**************************************************************************************************/
inline Vector4::Vector4(const float* f)
	: x(f[0]), y(f[1]), z(f[2]), w(f[3])
{ }

/**************************************************************************************************
* Copy constructor
**************************************************************************************************/
inline Vector4::Vector4(const Vector4& rhs)
	: x(rhs.x), y(rhs.y), z(rhs.z), w(rhs.w)
{ }

/**************************************************************************************************
* Constructor where x, y, z, and w values are specified
**************************************************************************************************/
inline Vector4::Vector4(float x, float y, float z, float w)
	: x(x), y(y), z(z), w(w)
{ }

/**************************************************************************************************
* Destructor
**************************************************************************************************/
inline Vector4::~Vector4(void)
{ }

/**************************************************************************************************
* Cast to non-const float array
**************************************************************************************************/
inline Vector4::operator float*(void) {
	return(float*) this;
}

/**************************************************************************************************
* Cast to const float array
**************************************************************************************************/
inline Vector4::operator const float*(void) {
	return (const float*) this;
}

/**************************************************************************************************
* Assignment operator
**************************************************************************************************/
inline Vector4& Vector4::operator=(const Vector4& rhs) {
	// Self-assignment guard
	if(this == &rhs) {
		return *this;
	}

	// Assign and return
	x = rhs.x;
	y = rhs.y;
	z = rhs.z;
	w = rhs.w;

	return *this;
}

/**************************************************************************************************
* Addition assignment operator
**************************************************************************************************/
inline Vector4& Vector4::operator+=(const Vector4& rhs) {
	x += rhs.x;
	y += rhs.y;
	z += rhs.z;
	w += rhs.w;
	return *this;
}

/**************************************************************************************************
* Subtraction assignment operator
**************************************************************************************************/
inline Vector4& Vector4::operator-=(const Vector4& rhs) {
	x -= rhs.x;
	y -= rhs.y;
	z -= rhs.z;
	w -= rhs.w;
	return *this;
}

/**************************************************************************************************
* Multiplication assignment operator
**************************************************************************************************/
inline Vector4& Vector4::operator*=(float rhs) {
	x *= rhs;
	y *= rhs;
	z *= rhs;
	w *= rhs;
	return *this;
}

/**************************************************************************************************
* Division assignment operator
**************************************************************************************************/
inline Vector4& Vector4::operator/=(float rhs) {
	const float f = 1.0f / rhs;
	x *= f;
	y *= f;
	z *= f;
	w *= f;
	return *this;
}

/**************************************************************************************************
* Returns positive copy of the vector
**************************************************************************************************/
inline Vector4 Vector4::operator+(void) const {
	return *this;
}

/**************************************************************************************************
* Returns a negated copy of the vector
**************************************************************************************************/
inline Vector4 Vector4::operator-(void) const {
	return Vector4(-x, -y, -z, -w);
}

/**************************************************************************************************
* Returns sum of two vectors
**************************************************************************************************/
inline Vector4 Vector4::operator+(const Vector4& rhs) const {
	return Vector4(x + rhs.x, y + rhs.y, z + rhs.z, w + rhs.w);
}

/**************************************************************************************************
* Return difference between two vectors
**************************************************************************************************/
inline Vector4 Vector4::operator-(const Vector4& rhs) const {
	return Vector4(x - rhs.x, y - rhs.y, z - rhs.z, w - rhs.w);
}

/**************************************************************************************************
* Return a vector multiplied by a scalar
**************************************************************************************************/
inline Vector4 Vector4::operator*(float rhs) const {
	return Vector4(x * rhs, y * rhs, z * rhs, w * rhs);
}

/**************************************************************************************************
* Return a vector divided by a scalar
**************************************************************************************************/
inline Vector4 Vector4::operator/(float rhs) const {
	const float f = 1.0f / rhs;
	return Vector4(x * f, y * f, z * f, w * f);
}

/**************************************************************************************************
* Return a vector multiplied by a scalar
**************************************************************************************************/
inline Vector4 operator*(float lhs, const Vector4& rhs) {
	return Vector4(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z, lhs * rhs.w);
}

/**************************************************************************************************
* Equivalence
**************************************************************************************************/
inline bool Vector4::operator==(const Vector4& rhs) const {
	return (x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w);
}

/**************************************************************************************************
* Non-equivalence
**************************************************************************************************/
inline bool Vector4::operator!=(const Vector4& rhs) const {
	return (x != rhs.x || y != rhs.y || z != rhs.z || w != rhs.w);
}

/**************************************************************************************************
* Length
**************************************************************************************************/
inline float Vec4Length(const Vector4* pV) {
	return sqrtf(pV->x*pV->x + pV->y*pV->y + pV->z*pV->z + pV->w*pV->w);
}

/**************************************************************************************************
* Squared length
**************************************************************************************************/
inline float Vec4LengthSqr(const Vector4* pV) {
	return (pV->x*pV->x + pV->y*pV->y + pV->z*pV->z + pV->w*pV->w);
}

/**************************************************************************************************
* Dot product
**************************************************************************************************/
inline float Vec4Dot(const Vector4* pV1, const Vector4* pV2) {
	return pV1->x*pV2->x + pV1->y*pV2->y + pV1->z*pV2->z + pV1->w*pV2->w;
}

/**************************************************************************************************
* Add two vectors
**************************************************************************************************/
inline Vector4* Vec4Add(Vector4* pOut, const Vector4* pV1, const Vector4* pV2) {
	pOut->x = pV1->x + pV2->x;
	pOut->y = pV1->y + pV2->y;
	pOut->z = pV1->z + pV2->z;
	pOut->w = pV1->w + pV2->w;
	return pOut;
}

/**************************************************************************************************
* Return the difference between two vectors
**************************************************************************************************/
inline Vector4* Vec4Sub(Vector4* pOut, const Vector4* pV1, const Vector4* pV2) {
	pOut->x = pV1->x - pV2->x;
	pOut->y = pV1->y - pV2->y;
	pOut->z = pV1->z - pV2->z;
	pOut->w = pV1->w - pV2->w;
	return pOut;
}

/**************************************************************************************************
* Return a vector comprised of the minimum components of each vector
**************************************************************************************************/
inline Vector4* Vec4Minimize(Vector4* pOut, const Vector4* pV1, const Vector4* pV2) {
	pOut->x = pV1->x < pV2->x ? pV1->x : pV2->x;
	pOut->y = pV1->z < pV2->y ? pV1->y : pV2->y;
	pOut->z = pV1->y < pV2->z ? pV1->z : pV2->z;
	pOut->w = pV1->w < pV2->w ? pV1->w : pV2->w;
	return pOut;
}

/**************************************************************************************************
* Return a vector comprised of the maximum components of each vector
**************************************************************************************************/
inline Vector4* Vec4Maximize(Vector4* pOut, const Vector4* pV1, const Vector4* pV2) {
	pOut->x = pV1->x > pV2->x ? pV1->x : pV2->x;
	pOut->y = pV1->z > pV2->y ? pV1->y : pV2->y;
	pOut->z = pV1->y > pV2->z ? pV1->z : pV2->z;
	pOut->w = pV1->w > pV2->w ? pV1->w : pV2->w;
	return pOut;
}

/**************************************************************************************************
* Scale the vector by a given factor
**************************************************************************************************/
inline Vector4* Vec4Scale(Vector4* pOut, const Vector4* pV, float s) {
	pOut->x = pV->x * s;
	pOut->y = pV->y * s;
	pOut->z = pV->z * s;
	pOut->w = pV->w * s;
	return pOut;
}

/**************************************************************************************************
* Return the interpolated vector
**************************************************************************************************/
inline Vector4* Vec4Lerp(Vector4* pOut, const Vector4* pV1, const Vector4* pV2, float s) {
	pOut->x = pV1->x + s * (pV2->x - pV1->x);
	pOut->y = pV1->y + s * (pV2->y - pV1->y);
	pOut->z = pV1->z + s * (pV2->z - pV1->z);
	pOut->w = pV1->w + s * (pV2->w - pV1->w);	
	return pOut;
}